React-Leaflet - 更新存储在状态中的 Circle 对象,或者优化 Circles 加载速度
React-Leaflet - Updating Circle objects that are stored in state, or alternatively optimizing Circles loading speed
我正在尝试创建一个包含大量圆形对象的地图。这些圆圈的颜色会根据用户输入而改变。可以一次改变很多颜色,我想尽快呈现变化。
为了节省每次用户更改内容和地图重新渲染时创建 Circles 的时间,我考虑将 Circle 对象存储在状态数组中。然后当用户更改某些内容时,我想更新 Circles 的属性,但不使用复制方法等(因为它与仅创建一次 Circle 对象的想法相矛盾)。
我考虑过制作一个存储颜色的并行数组,该数组将由用户更新,并在每个 Circle 对象的 pathOptions 中存储对该数组中并行位置的引用,但我不确定该怎么做这个。
或者,我很乐意听到有关如何优化速度的任何其他说明。
基本版本,应用程序从数组中正确加载圆圈,颜色是静态的:
import locations from "../locations.json"
function Map(props){
const [circlesArray, setCirclesArray] = useState([])
useEffect(() => { //initializes the circlesArray
let tempCirclesArray = []
locations.map(location => {
let position = [location.coordinates[1], location.coordinates[0]]
tempCirclesArray.push(
<CircleMarker center={position} radius={4}
pathOptions={
color: "red",
fillColor: "red"
} //here pathOptions is predetermined
/>
)
})
setCirclesArray(tempCirclesArray)
}, [])
return(
<div>
<div id="mapid" ref={mapRef}>
<button onClick={clickTest}>helno</button>
<MapContainer center={defaultPositon} zoom={mapZoom} scrollWheelZoom={true}>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
//map and display the Circle objects
{
circlesArray.map(circle => {
return(circle)
})
}
</MapContainer>
</div>
</div>
)
将这些 CircleMarker
组件保持在状态中一点也不理想。来自 react-leaflet 文档:
By default these props should be treated as immutable, only the props explicitely documented as mutable in this page will affect the Leaflet element when changed.
更改这些道具不会重新渲染它们。
使用 refs 可以做得更好。我刚刚在这里回答了一个问题:How to open a specific popup on map load?
。您可以看到有关如何结合 refs 和 state 以到达底层传单元素的详细说明。在您的情况下,最好不要将所有这些 <CircleMaker>
组件保存在状态变量中。直接在您的组件中使用 locations.map
,并在该映射中将所有引用保存到一个对象:
import locations from "../locations.json"
const MyMapComponent = {
const circleRefs = React.useRef()
return (
<MapContainer {...MapContainerProps}>
<TileLayer />
{locations.map(location => {
let position = [location.coordinates[1], location.coordinates[0]]
return (
<CircleMarker
preferCanvas
center={position}
radius={4}
pathOptions={...options_you_want}
ref={(ref) => {
circleRefs.current[location.id] = ref;
}}
/>
)
})}
</MapContainer>
)
}
现在您有一个对象,circleRefs
,其中包含一个对象。该对象的键是每个 location
的唯一 id 值,值是任何这些 refs 上的 底层传单 L.circleMarker instance. With that, you can call leaflet's setStyle 方法。例如,circleRefs['some-unique-id'].setStyle({ fillColor: 'red' })
将设置该引用的样式。
通过这种方式,您可以在不强制重新渲染的情况下更改这些圆圈的颜色。这可以同时在很多圈子上完成,而不会造成巨大的性能损失 - 而不是卸载(和删除)圈子组件,传单的内部结构会重新着色 svg。
我还添加了 preferCanvas
道具,对于任何扩展 L.path(包括 L.circleMarker)的东西,选择使用 canvas 而不是 svgs。对于大量项目,这也有助于提高性能。
我正在尝试创建一个包含大量圆形对象的地图。这些圆圈的颜色会根据用户输入而改变。可以一次改变很多颜色,我想尽快呈现变化。
为了节省每次用户更改内容和地图重新渲染时创建 Circles 的时间,我考虑将 Circle 对象存储在状态数组中。然后当用户更改某些内容时,我想更新 Circles 的属性,但不使用复制方法等(因为它与仅创建一次 Circle 对象的想法相矛盾)。
我考虑过制作一个存储颜色的并行数组,该数组将由用户更新,并在每个 Circle 对象的 pathOptions 中存储对该数组中并行位置的引用,但我不确定该怎么做这个。
或者,我很乐意听到有关如何优化速度的任何其他说明。
基本版本,应用程序从数组中正确加载圆圈,颜色是静态的:
import locations from "../locations.json"
function Map(props){
const [circlesArray, setCirclesArray] = useState([])
useEffect(() => { //initializes the circlesArray
let tempCirclesArray = []
locations.map(location => {
let position = [location.coordinates[1], location.coordinates[0]]
tempCirclesArray.push(
<CircleMarker center={position} radius={4}
pathOptions={
color: "red",
fillColor: "red"
} //here pathOptions is predetermined
/>
)
})
setCirclesArray(tempCirclesArray)
}, [])
return(
<div>
<div id="mapid" ref={mapRef}>
<button onClick={clickTest}>helno</button>
<MapContainer center={defaultPositon} zoom={mapZoom} scrollWheelZoom={true}>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
//map and display the Circle objects
{
circlesArray.map(circle => {
return(circle)
})
}
</MapContainer>
</div>
</div>
)
将这些 CircleMarker
组件保持在状态中一点也不理想。来自 react-leaflet 文档:
By default these props should be treated as immutable, only the props explicitely documented as mutable in this page will affect the Leaflet element when changed.
更改这些道具不会重新渲染它们。
使用 refs 可以做得更好。我刚刚在这里回答了一个问题:How to open a specific popup on map load?
。您可以看到有关如何结合 refs 和 state 以到达底层传单元素的详细说明。在您的情况下,最好不要将所有这些 <CircleMaker>
组件保存在状态变量中。直接在您的组件中使用 locations.map
,并在该映射中将所有引用保存到一个对象:
import locations from "../locations.json"
const MyMapComponent = {
const circleRefs = React.useRef()
return (
<MapContainer {...MapContainerProps}>
<TileLayer />
{locations.map(location => {
let position = [location.coordinates[1], location.coordinates[0]]
return (
<CircleMarker
preferCanvas
center={position}
radius={4}
pathOptions={...options_you_want}
ref={(ref) => {
circleRefs.current[location.id] = ref;
}}
/>
)
})}
</MapContainer>
)
}
现在您有一个对象,circleRefs
,其中包含一个对象。该对象的键是每个 location
的唯一 id 值,值是任何这些 refs 上的 底层传单 L.circleMarker instance. With that, you can call leaflet's setStyle 方法。例如,circleRefs['some-unique-id'].setStyle({ fillColor: 'red' })
将设置该引用的样式。
通过这种方式,您可以在不强制重新渲染的情况下更改这些圆圈的颜色。这可以同时在很多圈子上完成,而不会造成巨大的性能损失 - 而不是卸载(和删除)圈子组件,传单的内部结构会重新着色 svg。
我还添加了 preferCanvas
道具,对于任何扩展 L.path(包括 L.circleMarker)的东西,选择使用 canvas 而不是 svgs。对于大量项目,这也有助于提高性能。